/*
 *  lock_util.cc, Copyright (c) 2016, mogujie.com
 *  All rights reserved
 *
 *  Created on: 2016年2月28日
 *      Author: yongxue@mogujie.com
 */

#include <sys/time.h>

#include "lock_util.h"

namespace lock {

/**************************************************
 * Mutex
 */
MutexException::MutexException(IN const string& msg, IN int sys_code) {
	string tmp(strerror(sys_code));
	set_msg(("Mutex: " + msg + ": " + tmp));
	set_code(sys_code);
}

Mutex::Mutex() {
	pthread_mutexattr_t attr;
	if (pthread_mutexattr_t(&attr) != 0) {
		throw MutexException("pthread_mutexattr_t error", errno);
	}

	// pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
	if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT) != 0) {
		throw MutexException("pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT) error", errno);
	}

	if (pthread_mutex_init(&m_mutex, &attr) != 0) {
		throw MutexException("pthread_mutex_init error", errno);
	}

	if (pthread_mutexattr_destroy(&attr) != 0) {
		throw MutexException("pthread_mutexattr_destroy error", errno);
	}
}

Mutex::~Mutex() {
	if (pthread_mutex_destroy(&m_mutex) != 0) {
		throw MutexException("pthread_mutex_destroy error", errno);
	}
}


void Mutex::lock() {
	int ret = pthread_mutex_lock(&m_mutex);
	if (ret != 0) {
		throw MutexException("pthread_mutex_lock error", errno);
	}
}

bool Mutex::tryLock() {
	int ret = pthread_mutex_trylock(&m_mutex);
	if (ret == EBUSY) {
		return false;
	}
	else if (ret != 0) {
		throw MutexException("pthread_mutex_trylock error", errno);
	}
	return true;
}

void Mutex::unlock() {
	int ret = pthread_mutex_unlock(&m_mutex);
	if (ret != 0) {
		throw MutexException("pthread_mutex_unlock error", errno);
	}
}


/**************************************************
 * Cond
 */
CondException::CondException(IN const string& msg, IN int sys_code) {
	string tmp(strerror(sys_code));
	set_msg(("Cond: " + msg + ": " + tmp));
	set_code(sys_code);
}


Cond::Cond() {
	int ret;

	pthread_condattr_t attr;				// 条件变量的属性
	ret = pthread_condattr_init(&attr);
	if (ret) {
		throw CondException("pthread_condattr_init error", errno);
	}

	if (pthread_cond_init(&m_cond, &attr) != 0) {
		throw CondException("pthread_cond_init error", errno);
	}

	// 释放资源
	if (pthread_condattr_destroy(&attr) != 0) {
		throw CondException("pthread_condattr_destroy error", errno);
	}
}

Cond::~Cond() {
	if (pthread_cond_destroy(&m_cond) != 0) {
		throw CondException("pthread_cond_destroy error", errno);
	}
}

void Cond::signal() {
	if (pthread_cond_signal(&m_cond) != 0) {
		throw CondException("pthread_cond_signal error", errno);
	}
	return;
}

void Cond::broadcast() {
	if (pthread_cond_broadcast(&m_cond) != 0) {
		throw CondException("pthread_cond_broadcast error", errno);
	}
	return;
}

timespec Cond::abstime(IN int millsecond) const {
	struct timeval tv;

	gettimeofday(&tv, 0);
//	DCTimeProvider::getInstance()->getNow(&tv);

	int64_t it  = tv.tv_sec * (int64_t)1000000 + tv.tv_usec + (int64_t)millsecond * 1000;

	tv.tv_sec   = it / (int64_t)1000000;
	tv.tv_usec  = it % (int64_t)1000000;

	timespec ts;
	ts.tv_sec   = tv.tv_sec;
	ts.tv_nsec  = tv.tv_usec * 1000;
	return ts;
}
}


